﻿<!DOCTYPE html>
<!--[if IE]><![endif]-->
<html>
  
  <head>
    <!-- Global site tag (gtag.js) - Google Analytics -->
    <script async="" src="https://www.googletagmanager.com/gtag/js?id=UA-39155502-5"></script>
    <script>
      window.dataLayer = window.dataLayer || [];
      function gtag(){dataLayer.push(arguments);}
      gtag('js', new Date());
  
      gtag('config', 'UA-39155502-5');
    </script>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <title>String templates | MongoDB.Entities </title>
    <meta name="viewport" content="width=device-width">
    <meta name="title" content="String templates | MongoDB.Entities ">
    <meta name="generator" content="docfx 2.58.0.0">
    <meta name="description" content="A data access library for MongoDB with an elegant api, LINQ support and built-in entity relationship management.">
    <link rel="shortcut icon" href="../images/favicon.ico">
    <link rel="stylesheet" href="../styles/docfx.vendor.css">
    <link rel="stylesheet" href="../styles/docfx.css">
    <link rel="stylesheet" href="../styles/main.css">
    <meta property="docfx:navrel" content="../toc.html">
    <meta property="docfx:tocrel" content="toc.html">
    
    <meta property="docfx:rel" content="../">
    <meta property="docfx:newtab" content="true">
    <meta property="og:title" content="MongoDB.Entities">
    <meta property="og:site_name" content="MongoDB.Entities">
    <meta property="og:url" content="https://mongodb-entities.com">
    <meta property="og:description" content="A data access library for MongoDB with an elegant api, LINQ support and built-in entity relationship management,">
    <meta property="og:type" content="website">
    <meta property="og:image" content="https://mongodb-entities.com/images/social-square.png">  
  </head>
  <body data-spy="scroll" data-target="#affix" data-offset="120">
    <div id="wrapper">
      <header>
        
        <nav id="autocollapse" class="navbar navbar-inverse ng-scope" role="navigation">
          <div class="container">
            <div class="navbar-header">
              <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#navbar">
                <span class="sr-only">Toggle navigation</span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
              </button>
              
              <a class="navbar-brand" href="../index.html">
                <img id="logo" class="svg" src="../images/icon.png" alt="">
              </a>
            </div>
            <div class="collapse navbar-collapse" id="navbar">
              <form class="navbar-form navbar-right" role="search" id="search">
                <div class="form-group">
                  <input type="text" class="form-control" id="search-query" placeholder="Search" autocomplete="off">
                </div>
              </form>
            </div>
          </div>
        </nav>
        
        <div class="subnav navbar navbar-default">
          <div class="container hide-when-search" id="breadcrumb">
            <ul class="breadcrumb">
              <li></li>
            </ul>
          </div>
        </div>
      </header>
      <div class="container body-content">
        
        <div id="search-results">
          <div class="search-list">Search Results for <span></span></div>
          <div class="sr-items">
            <p><i class="glyphicon glyphicon-refresh index-loading"></i></p>
          </div>
          <ul id="pagination" data-first="First" data-prev="Previous" data-next="Next" data-last="Last"></ul>
        </div>
      </div>
      <div role="main" class="container body-content hide-when-search">
        
        <div class="sidenav hide-when-search">
          <a class="btn toc-toggle collapse" data-toggle="collapse" href="#sidetoggle" aria-expanded="false" aria-controls="sidetoggle">Show / Hide Table of Contents</a>
          <div class="sidetoggle collapse" id="sidetoggle">
            <div id="sidetoc"></div>
          </div>
        </div>
        <div class="article row grid-right">
          <div class="col-md-10">
            <article class="content wrap" id="_content" data-uid="">
<h1 id="string-templates">String templates</h1>

<p>the mongodb driver has it's limits and sometimes you need to compose queries either by hand or using a query editor/composer. to be able to run those queries and inject values from your C# code, you're required to compose <code>BsonDocuments</code> or do string concatenation which leads to an ugly, unreadable, magic string infested mess.</p>
<p>in order to combat this problem and also to couple your C# entity schema to raw queries, this library offers a templating system based on tag replacements.</p>
<p>take the following find query for example:</p>
<pre><code class="lang-java">db.Book.find(
  {
    Title : 'book_name',
    Price : book_price
  }
)
</code></pre>
<p>to couple this text query to your C# models and pass in the values for title and price, you simply surround the parts you want replaced with <code>&lt;</code> and <code>&gt;</code> in order to turn them in to replacement tags/markers like this:</p>
<pre><code class="lang-java">db.Book.find(
  {
    &lt;Title&gt; : '&lt;book_name&gt;',
    &lt;Price&gt; : &lt;book_price&gt;
  }
)
</code></pre>
<p>the templating system is based on a special class called <code>Template</code>. You simply instantiate a 'Template' object supplying the tagged/marked text query to the constructor. then you chain method calls on the Template object to replace each tag you've marked on the query like so:</p>
<pre><code class="lang-csharp">var query = new Template&lt;Book&gt;(@&quot;
{
  &lt;Title&gt; : '&lt;book_name&gt;',
  &lt;Price&gt; : &lt;book_price&gt;
}&quot;)
.Path(b =&gt; b.Title)    
.Path(b =&gt; b.Price)
.Tag(&quot;book_name&quot;,&quot;The Power Of Now&quot;)
.Tag(&quot;book_price&quot;,&quot;10.95&quot;);

var result = await DB.Find&lt;Book&gt;()
                     .Match(query)
                     .ExecuteAsync();
</code></pre>
<p>the resulting query sent to mongodb is this:</p>
<pre><code class="lang-java">db.Book.find(
  {
    Title : 'The Power Of Now',
    Price : 10.95
  }
)
</code></pre>
<p>the <code>.Tag()</code> method simply replaces matching tags on the text query with the supplied value. you don't have to use the <code>&lt;</code> and <code>&gt;</code> characters while using the <code>.Tag()</code> method. infact, avoid it as the tags won't match if you use them.</p>
<p>the <code>.Path()</code> method is one of many offered by the <code>Prop</code> class you can use to get the full 'dotted' path of a property by supplying a lambda/member expression. please see the documentation of the 'Prop' class <a href="Extras-Prop.html">here</a> for the other methods available.</p>
<p>notice, that most of these 'Prop' methods only require a single parameter. whatever member expression you supply to them gets converted to a property/field path like this:</p>
<blockquote>
<p>expression: x =&gt; x.Authors[0].Books[0].Title</p>
</blockquote>
<blockquote>
<p>resulting path: Authors.Books.Title</p>
</blockquote>
<p>if your text query has a tag <code>&lt;Authors.Books.Title&gt;</code> it will get replaced by the resulting path from the 'Prop' class method.</p>
<p>the template system will throw an exception in the event of the following 3 scenarios.</p>
<ol>
<li>the input query/text has no tags marked using <code>&lt;</code> and <code>&gt;</code> characters.</li>
<li>the input query has tags that you forget to specify replacements for.</li>
<li>you have specified replacements that doesn't have a matching tag in the query.</li>
</ol>
<p>this kind of runtime errors are preferable than your code failing silently because the queries didn't produce any results or produced the wrong results.</p>
<h1 id="examples">Examples</h1>
<h3 id="aggregation-pipeline">Aggregation pipeline</h3>
<pre><code class="lang-csharp">var pipeline = new Template&lt;Book&gt;(@&quot;
[
    {
      $match: { &lt;Title&gt;: '&lt;book_name&gt;' }
    },
    {
      $sort: { &lt;Price&gt;: 1 }
    },
    {
      $group: {
        _id: '$&lt;AuthorId&gt;',
        product: { $first: '$$ROOT' }
      }
    },
    {
      $replaceWith: '$product'
    }
]&quot;)
.Path(b =&gt; b.Title)
.Path(b =&gt; b.Price)
.Path(b =&gt; b.AuthorId)
.Tag(&quot;book_name&quot;, &quot;MongoDB Templates&quot;);

var book = await DB.PipelineSingleAsync(pipeline);
</code></pre>
<h3 id="aggregation-pipeline-with-different-result-type">Aggregation pipeline with different result type</h3>
<pre><code class="lang-csharp">var pipeline = new Template&lt;Book, Author&gt;(@&quot;
[
    {
        $match: { _id: &lt;book_id&gt; }
    },
    {
        $lookup: 
        {
            from: '&lt;author_collection&gt;',
            localField: '&lt;AuthorID&gt;',
            foreignField: '_id',
            as: 'authors'
        }
    },
    {
        $replaceWith: { $arrayElemAt: ['$authors', 0] }
    },
    {
        $set: { &lt;Age&gt; : 34 }
    }
]&quot;)
.Tag(&quot;book_id&quot;, &quot;ObjectId('5e572df44467000021005692')&quot;)
.Tag(&quot;author_collection&quot;, DB.Entity&lt;Author&gt;().CollectionName())
.Path(b =&gt; b.AuthorID)
.PathOfResult(a =&gt; a.Age);

var authors = await DB.PipelineAsync(pipeline);
</code></pre>
<h3 id="find-with-match-expression">Find with match expression</h3>
<pre><code class="lang-csharp">var query = new Template&lt;Author&gt;(@&quot;
{
  $and: [
    { $gt: [ '$&lt;Age&gt;', &lt;author_age&gt; ] },
    { $eq: [ '$&lt;Surname&gt;', '&lt;author_surname&gt;' ] }
  ]
}&quot;)
.Path(a =&gt; a.Age)
.Path(a =&gt; a.Surname)
.Tag(&quot;author_age&quot;, &quot;54&quot;)
.Tag(&quot;author_surname&quot;, &quot;Tolle&quot;);

var authors = await DB.Find&lt;Author&gt;()
                      .MatchExpression(query)
                      .ExecuteAsync();
</code></pre>
<h3 id="update-with-aggregation-pipeline">Update with aggregation pipeline</h3>
<pre><code class="lang-csharp">var pipeline = new Template&lt;Author&gt;(@&quot;
[
  { $set: { &lt;FullName&gt;: { $concat: ['$&lt;Name&gt;',' ','$&lt;Surname&gt;'] } } },
  { $unset: '&lt;Age&gt;'}
]&quot;)             
.Path(a =&gt; a.FullName)
.Path(a =&gt; a.Name)
.Path(a =&gt; a.Surname)
.Path(a =&gt; a.Age);

await DB.Update&lt;Author&gt;()
        .Match(a =&gt; a.ID == &quot;xxxxx&quot;)
        .WithPipeline(pipeline)
        .ExecutePipelineAsync();
</code></pre>
<h3 id="update-with-array-filters">Update with array filters</h3>
<pre><code class="lang-csharp">var filters = new Template&lt;Author&gt;(@&quot;
[
  { '&lt;a.Age&gt;': { $gte: &lt;age&gt; } },
  { '&lt;b.Name&gt;': 'Echkart Tolle' }
]&quot;)
.Elements(0, author =&gt; author.Age)
.Elements(1, author =&gt; author.Name);
.Tag(&quot;age&quot;, &quot;55&quot;)        

var update = new Template&lt;Book&gt;(@&quot;
{ $set: { 
    '&lt;Authors.$[a].Age&gt;': &lt;age&gt;,
    '&lt;Authors.$[b].Name&gt;': '&lt;name&gt;'
  } 
}&quot;)
.PosFiltered(book =&gt; book.Authors[0].Age)
.PosFiltered(book =&gt; book.Authors[1].Name)
.Tag(&quot;age&quot;, &quot;55&quot;)
.Tag(&quot;name&quot;, &quot;Updated Name&quot;);

await DB.Update&lt;Book&gt;()
        .Match(book =&gt; book.ID == &quot;xxxxxxxx&quot;)
        .WithArrayFilters(filters)
        .Modify(update)
        .ExecuteAsync();
</code></pre>
<h3 id="dynamically-append-stages-to-the-pipeline">Dynamically append stages to the pipeline</h3>
<pre><code class="lang-csharp">var pipeline = new Template&lt;Book&gt;(&quot;[{ $match: { &lt;Title&gt;: '&lt;book_name&gt;' }}]&quot;);

if (sortByPrice)
{
    pipeline.AppendStage(&quot;{ $sort: { &lt;Price&gt;: 1 } }&quot;);
    pipeline.Path(b =&gt; b.Price);
}

pipeline
.Path(b =&gt; b.Title)
.Tag(&quot;book_name&quot;, &quot;MongoDB Templates&quot;);

var books = await DB.PipelineAsync(pipeline);
</code></pre>
</article>
          </div>
          
          <div class="hidden-sm col-md-2" role="complementary">
            <div class="sideaffix">
              <div class="contribution">
                <ul class="nav">
                </ul>
              </div>
              <nav class="bs-docs-sidebar hidden-print hidden-xs hidden-sm affix" id="affix">
                <h5>In This Article</h5>
                <div></div>
              </nav>
            </div>
          </div>
        </div>
      </div>
      
      <footer>
        <div class="grad-bottom"></div>
        <div class="footer">
          <div class="container">
            <span class="pull-right">
              <a href="#top">Back to top</a>
            </span>
            Developed by <a href='https://github.com/dj-nitehawk'>Đĵ ΝιΓΞΗΛψΚ</a> and <a href='https://github.com/dj-nitehawk/MongoDB.Entities/graphs/contributors'>contributors</a> / Licensed under <a href='https://github.com/dj-nitehawk/MongoDB.Entities/blob/master/LICENSE'>MIT</a> / Website generated by <a href='https://dotnet.github.io/docfx/'>DocFX</a>
            
          </div>
        </div>
      </footer>
    </div>
    
    <script type="text/javascript" src="../styles/docfx.vendor.js"></script>
    <script type="text/javascript" src="../styles/docfx.js"></script>
    <script type="text/javascript" src="../styles/main.js"></script>
  </body>
</html>
